home *** CD-ROM | disk | FTP | other *** search
- ; Wb-tree File Based Associative String Data Base System.
- ; Copyright (c) 1991, 1992, 1993 Holland Mark Martin
- ;
- ;Permission to use, copy, modify, and distribute this software and its
- ;documentation for educational, research, and non-profit purposes and
- ;without fee is hereby granted, provided that the above copyright
- ;notice appear in all copies and that both that copyright notice and
- ;this permission notice appear in supporting documentation, and that
- ;the name of Holland Mark Martin not be used in advertising or
- ;publicity pertaining to distribution of the software without specific,
- ;written prior consent in each case. Permission to incorporate this
- ;software into commercial products can be obtained from Jonathan
- ;Finger, Holland Mark Martin, 174 Middlesex Turnpike, Burlington, MA,
- ;01803-4467, USA. Holland Mark Martin makes no representations about
- ;the suitability or correctness of this software for any purpose. It
- ;is provided "as is" without express or implied warranty. Holland Mark
- ;Martin is under no obligation to provide any services, by way of
- ;maintenance, update, or otherwise.
-
- ;; routines in this file return success codes
-
- (require (in-vicinity (program-vicinity) "sys"))
-
- ;;;; BT Stuff
-
- (define (bt-open seg blk-num han wcb)
- (if (and (>= seg 0) (< seg NUM-SEGS) (SEG-STR seg)) ;allocated
- (let ((ent (get-ent seg blk-num ACCREAD)))
- (cond ((not ent) UNKERR)
- ((not (root? (ENT-BLK ent)))
- (release-ent! ent ACCREAD)
- (fprintf diagout ">>>>ERROR<<<<BT-OPEN: not a root %d:%d\\n"
- seg blk-num)
- ;;; (check-access!)
- ARGERR)
- (else
- (HAN-SET-SEG! han seg)
- (HAN-SET-NUM! han blk-num)
- (HAN-SET-TYP! han (BLK-TYP (ENT-BLK ent))) ;TBD improve. (eh?)
- (HAN-SET-LAST! han blk-num)
- (if (BLK-TYP? (ENT-BLK ent) DIR-TYP)
- (set! wcb (logior wcb (+ WCB-SAP WCB-SAR))))
- (HAN-SET-WCB! han wcb)
- (release-ent! ent ACCREAD)
- ;;; (check-access!)
- (HAN-TYP han))))
- ARGERR))
-
- (define (bt-create seg typ han wcb)
- (define ent (create-new-blk-ent seg))
- (cond ((not ent) NOROOM)
- (else (let* ((blk-num (ENT-ID ent)))
- (init-leaf-blk! (ENT-BLK ent) blk-num typ)
- (ENT-SET-DTY! ent #t)
- (ENT-SET-PUS! ent 0)
- (ent-write ent)
- (HAN-SET-SEG! han seg)
- (HAN-SET-NUM! han blk-num)
- (HAN-SET-TYP! han typ)
- (HAN-SET-LAST! han blk-num)
- (if (eqv? typ DIR-TYP)
- (set! wcb (logior wcb (+ WCB-SAP WCB-SAR))))
- (HAN-SET-WCB! han wcb)
- (release-ent! ent ACCWRITE)
- ;;; (check-access!)
- SUCCESS))))
-
- (define (bt-close han)
- (HAN-SET-SEG! han 0)
- (HAN-SET-NUM! han 0)
- (HAN-SET-TYP! han 0)
- (HAN-SET-LAST! han 0)
- SUCCESS)
-
- (define clever-cache-enable #t)
-
- ;; NOTE: Please note that most of the data-manipulating commands here
- ;; can return NOTPRES, with the followng meanings:
- ;; GET: no such key
- ;; NEXT: no NEXT key (ie, key given was LAST key)
- ;; PREV: no PREV key (ie, key given was FIRST key)
- ;; REM: KEY was not found
- ;; REM-RANGE: ??
- ;; PUT: NOT USED (could be symmetric w/WRITE)
- ;; WRITE: key WAS found, so no write done
-
- (define (bt-get han key-str k-len ans-str)
- (define pkt (make-vector PKT-SIZE))
- (define ent #f)
- ;;; (fprintf diagout "bt-get %d:%ld %.*s\\n" (HAN-SEG han) (HAN-ID han)
- ;;; (max 0 k-len) key-str)
- (set! ent (chain-find-ent han ACCREAD key-str k-len pkt))
- (cond ((not ent) (set! get-fct (+ 1 get-fct))
- UNKERR)
- ((not (eq? (MATCH-TYPE pkt) MATCH))
- (set! get-ct (+ 1 get-ct))
- (release-ent! ent ACCREAD)
- NOTPRES)
- (else
- (let ((alen (get-this-val (ENT-BLK ent) (MATCH-POS pkt) ans-str)))
- (set! get-ct (+ 1 get-ct))
- (release-ent! ent ACCREAD)
- alen))))
-
- (define (bt-next han key-str k-len ans-str)
- (define pkt (make-vector PKT-SIZE))
- (define ent #f)
- ; (fprintf diagout "bt-next %d:%ld %.*s\\n" (HAN-SEG han) (HAN-ID han)
- ; (max 0 k-len) key-str)
- (set! ent (chain-find-ent han ACCREAD key-str k-len pkt))
- (cond ((not ent)
- (set! next-fct (+ 1 next-fct))
- UNKERR)
- (else
- (set! next-ct (+ 1 next-ct))
- (let ((res (chain-next ent key-str k-len ans-str pkt)))
- (if clever-cache-enable (HAN-SET-LAST! han (BLK-TO-CACHE pkt)))
- res))))
-
- (define (bt-prev han key-str k-len ans-str)
- (define pkt (make-vector PKT-SIZE))
- (define ent #f)
- ; (fprintf diagout "bt-prev %d:%ld %.*s\\n" (HAN-SEG han) (HAN-ID han)
- ; (max 0 k-len) key-str)
- (set! ent (chain-find-prev-ent han ACCREAD key-str k-len pkt))
- (and ent (set! ent (prev-k-ent ent key-str k-len LEAF pkt)))
- (cond ((not ent)
- (set! prev-fct (+ 1 prev-fct))
- UNKERR)
- (else
- (set! prev-ct (+ 1 prev-ct))
- (if (zero? (MATCH-POS pkt))
- (begin (release-ent! ent ACCREAD) NOTPRES)
- (let ((k-len2 (recon-this-key (ENT-BLK ent)
- (MATCH-POS pkt) ans-str 0 256)))
- (HAN-SET-LAST! han (ENT-ID ent))
- (release-ent! ent ACCREAD)
- k-len2)))))
-
- ;;; rem removes key and value. returns SUCCESS if found, #f if not.
-
- (define (bt-rem han key-str k-len ans-str)
- (define pkt (make-vector PKT-SIZE))
- (define ent #f)
- ; (fprintf diagout "bt-rem %d:%ld %.*s\\n" (HAN-SEG han) (HAN-ID han)
- ; (max 0 k-len) key-str)
- (cond ((< k-len 0)
- (fprintf diagout ">>>>ERROR<<<< bt-rem: bad length string %d\\n" k-len)
- ARGERR)
- (else
- (set! ent (chain-find-ent han ACCWRITE key-str k-len pkt))
- (cond (ent
- (set! rem-ct (+ 1 rem-ct))
- (let ((ans (chain-rem ent key-str k-len ans-str pkt (HAN-WCB han))))
- (release-ent! ent ACCWRITE)
- ans))
- (else
- (set! rem-fct (+ 1 rem-fct))
- UNKERR)))))
-
- ;;; rem-range removes [key1 .. key2) and their values.
- ;;; If key2<=key1 no deletion will occur (even if key1 is found).
- ;;; To make possible bounded-time operation rem-range will
- ;;; clean out at most BLK-LIMIT blocks at a time; if you dont care,
- ;;; give it -1 for BLK-LIMIT. Rem-range returns SUCCESS if the operation
- ;;; is complete, NOTPRES or RETRYERR if not (meaning you need to call it again).
- ;;; ***WARNING*** In the latter cases, it MODIFIES the KEY1 string
- ;;; so that the string args are correctly set up for the next call
- ;;; (The new length for KEY1 is in (KEY-LEN respkt)).
- ;;; Therefore, KEY-STR MUST BE A MAXIMUM-LENGTH STRING [!!]
-
- (define (bt-rem-range han key-str k-len key2-str k2-len)
- (define respkt (make-vector PKT-SIZE))
- (bt-scan han REM-SCAN key-str k-len key2-str k2-len #f #f respkt -1))
-
- ;;; put adds an key value pair to the database whose root is blk
-
- (define (bt-put han key-str k-len val-str v-len)
- (define ent #f)
- (define pkt (make-vector PKT-SIZE))
- ; (fprintf diagout "bt-put %d:%ld %.*s %.*s\\n"
- ; (HAN-SEG han) (HAN-ID han) (max 0 k-len) key-str v-len val-str)
- (cond ((or (> v-len 255) (> k-len 255) (< k-len 0))
- ARGERR)
- (else
- (set! ent (chain-find-ent han ACCWRITE key-str k-len pkt))
- (if ent
- (let ((res (chain-put ent key-str k-len val-str v-len pkt #f (HAN-WCB han))))
- (cond (res
- (if clever-cache-enable
- (HAN-SET-LAST! han (BLK-TO-CACHE pkt)))
- (set! put-ct (+ 1 put-ct))
- SUCCESS)
- (else
- (set! put-fct (+ 1 put-fct))
- UNKERR)))
- UNKERR))))
-
- ;; note: returns NOTPRES if the key is PRESENT, else writes it and returs SUCCESS.
-
- (define (bt-write han key-str k-len val-str v-len)
- (define ent #f)
- (define pkt (make-vector PKT-SIZE))
- (cond
- ((or (> v-len 255) (> k-len 255) (< k-len 0))
- ARGERR)
- (else
- (set! ent (chain-find-ent han ACCWRITE key-str k-len pkt))
- (if ent
- (if (eq? (MATCH-TYPE pkt) MATCH)
- (begin (release-ent! ent ACCWRITE) NOTPRES) ;DTY has not been set.
- (let ((res (chain-put ent key-str k-len val-str v-len pkt #f (HAN-WCB han))))
- (cond (res
- (if clever-cache-enable
- (HAN-SET-LAST! han (BLK-TO-CACHE pkt)))
- (set! put-ct (+ 1 put-ct))
- SUCCESS)
- (else
- (set! put-fct (+ 1 put-fct))
- UNKERR))))
- UNKERR))))
-
- ;;;; Segment procedures
-
- (define db-version-str "WB-trees 1a1")
- (define db-authors-str "A. Jaffer, J. Finger, R. Zito-Wolf")
-
- (define (seg-free? seg)
- (if (not lck-tab) (init-wb 75 150 2048))
- (cond ((or (negative? seg) (>= seg NUM-SEGS))
- (fprintf diagout ">>>>ERROR<<<< bad segment number %d\\n" seg)
- #f)
- ((and (not (SEG-PORT seg))
- (not (SEG-STR seg))
- (not (SEG-USED seg)))
- #t)
- (else #f)))
-
- ;TBD - need to lck seg here.
- ;; Segment will be read-only if MODE is #f.
-
- (define (open-seg seg name mode)
- (define bsiz #f)
- (define (errout reason-str)
- (fprintf diagout ">>>>ERROR<<<< not a database %s %s\\n" name reason-str)
- (blk-file-close (SEG-PORT seg))
- (SEG-SET-PORT! seg #f)
- (SEG-SET-STR! seg #f)
- (SEG-SET-USED! seg #f)
- TYPERR)
- (if (zero? mode) (set! mode #f))
- (cond
- ((not (seg-free? seg))
- (fprintf diagout ">>>>ERROR<<<< open-seg:segment in use %d\\n" seg)
- ARGERR)
- ((begin
- (set! bsiz (min-file-blk-size name))
- (set! bsiz (max (* 3 128) bsiz))
- ;;temporarily set bsiz so that we can get it from superblk
- (> bsiz blk-size))
- (fprintf diagout ">>>>ERROR<<<< unsupported bsiz %d > %d\\n" bsiz blk-size)
- ARGERR)
- (else
- (let loop ((file (if mode (blk-file-open-modify name bsiz)
- (blk-file-open-read-only name bsiz))))
- (cond
- ((if mode (output-port? file) (input-port? file))
- (SEG-SET-PORT! seg file)
- (SEG-SET-STR! seg name)
- (SEG-SET-USED! seg 2)
- (SEG-SET-BSIZ! seg bsiz)
- (SEG-SET-FLC-LEN! seg (if mode -1 -2)) ;-1 means to read in "FLC" image.
- ;-2 means read only.
- (let ((han (SEG-RT-HAN seg))
- (tmp-str (make-string 5))) ;this should be longer
- (cond
- ((err? (bt-open seg 0 han (+ WCB-SAP WCB-SAR))) ; superblock
- (errout "bt-open 0"))
- ((not (eq? 2 (bt-get han "BSIZ" 4 tmp-str)))
- (errout "BSIZ"))
- ((not (= bsiz (str2short tmp-str 0)))
- (blk-file-close file)
- (set! bsiz (str2short tmp-str 0))
- (cond
- ((> bsiz blk-size) (errout "BSIZ too big."))
- (else (loop (if mode (blk-file-open-modify name bsiz)
- (blk-file-open-read-only name bsiz))))))
- ((not (eq? 4 (bt-get han "USED" 4 tmp-str)))
- (errout "USED"))
- (else
- (SEG-SET-USED! seg (str2long tmp-str 0))
- (cond ((not (eq? 5 (bt-get han "FLD" 3 tmp-str)))
- (errout "FLD"))
- ((err? (bt-open seg (str2long tmp-str 1) (SEG-FL-HAN seg) WCB-SAR))
- (errout "FLC"))
- (else
- (if (not (eqv? (HAN-TYP (SEG-FL-HAN seg)) FRL-TYP))
- (fprintf diagout "Older type freelist - still supported.\\n"))
- (HAN-SET-WCB! (SEG-FL-HAN seg) WCB-SAR)
- seg))))))
- (else
- (if (if mode (input-port? file) (output-port? file)) (blk-file-close file))
- (fprintf diagout ">>>>ERROR<<<< could not open file %s\\n" name)
- IOERR))))))
-
- (define (close-seg seg hammer)
- (cond ((or (not (SEG-STR seg))
- (not (SEG-USED seg)))
- (fprintf diagout ">>>>ERROR<<<< close-seg: segment %d already closed\\n" seg)
- ARGERR)
- (else
- (flush-flc! seg 5) ;leave only enough blocks to fit in flc in superblock.
- (if (>= (SEG-FLC-LEN seg) 0)
- (let* ((tmp-str (make-string 20)))
- (do ((i (+ -1 (SEG-FLC-LEN seg)) (+ -1 i)))
- ((negative? i))
- (long2str! tmp-str (* 4 i) (vector-ref (SEG-FLC seg) i)))
- (bt-put (SEG-RT-HAN seg) "FLC" 3 tmp-str (* 4 (SEG-FLC-LEN seg)))
- (SEG-SET-FLC-LEN! seg -1)))
- (let ((ans (do-seg-buffers seg flush-buffer)))
- (cond ((or (success? ans) hammer)
- (if (not (success? ans)) (set! ans NOTPRES))
- (do-seg-buffers seg purge-buffer)
- (bt-close (SEG-RT-HAN seg))
- (bt-close (SEG-FL-HAN seg))
- (blk-file-close (SEG-PORT seg))
- (SEG-SET-PORT! seg #f)
- (SEG-SET-STR! seg #f)
- (SEG-SET-USED! seg #f)))
- ans))))
-
- (define (make-seg seg name bsiz)
- (cond
- ((or (not (seg-free? seg)) (not (try-lck (SEG-LCK seg))))
- (fprintf diagout ">>>>ERROR<<<< make-seg:segment in use %d\\n" seg)
- ARGERR)
- ((> bsiz blk-size)
- (fprintf diagout ">>>>ERROR<<<< unsupported bsiz %d > %d\\n" bsiz blk-size)
- (unlck! (SEG-LCK seg))
- ARGERR)
- (else
- (let ((file (blk-file-create name bsiz)))
- (cond
- ((output-port? file)
- (SEG-SET-PORT! seg file)
- (SEG-SET-BSIZ! seg bsiz)
- (SEG-SET-USED! seg 3)
- (SEG-SET-STR! seg name)
- (init-leaf-blk! empty-blk 0 DIR-TYP)
- (BLK-SET-TIME! empty-blk (get-universal-time))
- (blk-write file empty-blk bsiz 0)
- (init-leaf-blk! empty-blk 1 DIR-TYP)
- (BLK-SET-TIME! empty-blk (get-universal-time))
- (blk-write file empty-blk bsiz 1)
- (init-leaf-blk! empty-blk 2 FRL-TYP)
- (BLK-SET-TIME! empty-blk (get-universal-time))
- (blk-write file empty-blk bsiz 2)
- (blk-file-close file)
- (set! file (blk-file-open-modify name bsiz))
- (cond ((output-port? file)
- (SEG-SET-PORT! seg file)
- (unlck! (SEG-LCK seg))
- (let ((han (SEG-RT-HAN seg))
- (tmp-str (make-string 5)))
- (bt-open seg 0 han (+ WCB-SAP WCB-SAR))
- (bt-put han "" 0
- db-version-str (string-length db-version-str))
- (long2str! tmp-str 0 (SEG-USED seg))
- (bt-put han "USED" 4 tmp-str 4)
- (short2str! tmp-str 0 (SEG-BSIZ seg))
- (bt-put han "BSIZ" 4 tmp-str 2)
- (string-set! tmp-str 0 (integer->char 4))
- (long2str! tmp-str 1 1)
- (bt-put han "ROOT" 4 tmp-str 5)
- (long2str! tmp-str 1 2)
- (bt-put han "FLD" 3 tmp-str 5)
- (bt-put han "FLC" 3 "" 0)
- (if (> bsiz 128)
- (bt-put han "authors" 7
- db-authors-str (string-length db-authors-str)))
- (close-seg seg #f) ;don't close the segment if it is memory resident.
- ))
- (else
- (fprintf diagout ">>>>ERROR<<<< couldn't open fresh file %s\\n"
- name)
- (unlck! (SEG-LCK seg))
- IOERR)))
- (else (fprintf diagout ">>>>ERROR<<<< couldn't create new file %s\\n" name)
- (unlck! (SEG-LCK seg))
- IOERR))))))
-